package main

import (
	"bytes"         // 用于处理字节操作，例如创建字节缓冲
	"context"       // 用于控制取消、超时和传递请求相关的值
	"encoding/json" // 用于JSON的编码和解码
	"log"           // 提供日志记录功能
	"net/http"      // 提供HTTP客户端和服务器实现
	"os"            // 提供操作系统功能，如文件和信号处理
	"os/signal"     // 用于信号的处理
	"strings"       // 用于字符串处理
	"syscall"       // 系统调用的接口
	"time"          // 提供时间的显示和测量用的功能

	v1 "k8s.io/api/core/v1"                       // Kubernetes核心API v1版本
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // Kubernetes元数据API
	"k8s.io/apimachinery/pkg/watch"               // Kubernetes的资源监控功能
	"k8s.io/client-go/kubernetes"                 // Kubernetes客户端库
	"k8s.io/client-go/tools/clientcmd"            // Kubernetes配置命令行工具
)

// 全局变量，存储最新的资源版本号，用以确保我们的观察请求是基于最新状态
var lastResourceVersion string

func main() {
	// 设置kubeconfig路径，这是连接Kubernetes集群的认证配置文件
	kubeconfig := "/root/.kube/config"
	// 根据指定的kubeconfig创建集群配置
	config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
	if err != nil {
		log.Fatal(err) // 如果配置失败，记录错误并终止程序
	}

	// 使用生成的配置创建一个Kubernetes客户端
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		log.Fatal(err) // 如果客户端创建失败，记录错误并终止程序
	}

	// 尝试打开或创建一个日志文件用于记录Pod事件
	logFile, err := os.OpenFile("pod_event.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalf("无法打开日志文件：%v", err) // 如果文件打开失败，记录错误并终止程序
	}
	defer logFile.Close()  // 确保在函数返回前关闭文件
	log.SetOutput(logFile) // 设置日志输出到该文件

	// 创建一个信号通道用于监听系统信号
	sigs := make(chan os.Signal, 1)
	// 注册要接收的系统信号
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// 启动一个新的goroutine来运行Pod监控逻辑
	go func() {
		for {
			select {
			case <-sigs:
				// 当接收到终止信号时，记录日志并退出goroutine
				log.Println("接收到关闭信号，停止监控...")
				return
			default:
				// 在没有接收到终止信号时，继续监控Pod
				if err := watchPods(clientset); err != nil {
					log.Printf("监控错误：%v", err)  // 记录监控过程中的错误
					time.Sleep(1 * time.Second) // 发生错误时暂停一秒
				}
			}
		}
	}()

	// 阻塞主goroutine，等待上面启动的goroutine完成
	<-make(chan struct{})
}

func watchPods(clientset *kubernetes.Clientset) error {
	// 创建一个带取消功能的上下文
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel() // 确保在函数退出前取消上下文

	// 创建一个列表选项，用于观察Pod时过滤结果
	options := metav1.ListOptions{}
	if lastResourceVersion != "" {
		options.ResourceVersion = lastResourceVersion // 如果有存储的版本号，则使用该版本号进行观察，以减少不必要的数据传输
	}

	// 创建一个Pod资源的Watcher
	watcher, err := clientset.CoreV1().Pods(metav1.NamespaceAll).Watch(ctx, options)
	if err != nil {
		return err // 如果创建Watcher失败，则返回错误
	}
	defer watcher.Stop() // 确保在函数退出前停止Watcher

	// 创建一个定时器，用于定期检查Watcher的状态
	heartbeat := time.NewTicker(30 * time.Second)
	defer heartbeat.Stop() // 确保在函数退出前停止定时器

	for {
		select {
		case event, ok := <-watcher.ResultChan():
			if !ok {
				// 如果Watcher的结果通道被关闭，则返回并尝试重新连接
				log.Println("事件通道被关闭，将尝试重新连接...")
				return nil // 返回nil表示需要重新建立连接
			}
			// 处理接收到的事件
			processEvent(event)
			// 更新全局资源版本号，以便下次调用使用最新状态
			lastResourceVersion = event.Object.(*v1.Pod).ResourceVersion
		case <-heartbeat.C:
			// 定时检查心跳，确保连接活跃
			log.Println("发送心跳，确认watcher活跃...")
		}
	}
}

func processEvent(event watch.Event) {
	pod, ok := event.Object.(*v1.Pod)
	if !ok {
		log.Println("接收到的事件不是Pod类型") // 如果事件对象不是Pod类型，则记录并跳过处理
		return
	}
	if shouldIgnore(pod.Name) {
		log.Printf("忽略服务：%s\n", pod.Name) // 根据业务需求忽略特定Pod的事件
		return
	}

	// 将事件对象序列化为JSON格式
	jsonData, err := json.Marshal(event)
	if err != nil {
		log.Printf("序列化事件错误：%v\n", err) // 如果序列化失败，则记录错误
		return
	}

	// 发送序列化后的JSON数据到指定的URL
	//sendJSON("http://wenwo-cloud-basic-server-down-prd.wenwo.cn/server/status/push", jsonData)
	sendJSON("http://127.0.0.1:5000/webhook", jsonData)
}

func shouldIgnore(name string) bool {
	// 定义需要忽略的服务列表
	ignoreServices := []string{
		"apollo-config-server-0", "apollo-config-server-1", "apollo-config-server-2",
		"apollo-admin-server", "apollo-portal-server", "eureka-0", "eureka-1", "eureka-2",
		"swagger", "dubbo-admin", "zk-0", "zk-1", "zk-2",
	}
	for _, service := range ignoreServices {
		if strings.Contains(name, service) {
			return true // 如果Pod名称包含在忽略列表中，返回true
		}
	}
	return false // 如果不在忽略列表中，返回false
}

func sendJSON(url string, jsonData []byte) error {
	// 创建一个HTTP POST请求，内容类型为JSON
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
	if err != nil {
		log.Printf("创建HTTP请求失败：%v", err) // 记录创建请求的错误
		return err
	}
	req.Header.Set("Content-Type", "application/json") // 设置请求头

	// 发送HTTP请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Printf("HTTP请求失败：%v", err) // 记录HTTP请求的错误
		return err
	}
	defer resp.Body.Close() // 确保在函数返回前关闭响应体

	log.Printf("事件发送至：%s, 状态码为：%s", url, resp.Status) // 记录请求的响应状态
	return nil
}
